#!/bin/bash
#功能函数
funcs=`which functions.sh`
if [ "$funcs" != "" ] ;then
    . $funcs
else
    funcs=`dirname $0`/functions.sh
    echo "$PWD"
    echo "funcs=$funcs"
    if [ "$funcs" != "" ] ;then
	. $funcs
    else
	exit
    fi
fi
def_allowednets="172.20.120.0/16"
toolchains_list="arm-eabi-4.4.3  arm-linux-androideabi-4.4.x"
toolchains_dir=$HOME/workspace/gphone/toolchain
def_jobs=4
pkgs_list="distcc distcc-pump dmucs"
######################################


function setting_etc_default_distcc()
{
  echoTextBlue "Setting /etc/default/distcc ......"
  src_file=/etc/default/distcc
  dst_file=/tmp/etc_default_distcc
  cp $src_file $dst_file -rf
  sh_sed_file_r_row_include_xxx $dst_file "^STARTDISTCC="  "STARTDISTCC=\"true\"" false 
  sh_sed_file_r_row_include_xxx $dst_file "^ALLOWEDNETS="  "ALLOWEDNETS=\"$def_allowednets\""  false
  sh_sed_file_r_row_include_xxx $dst_file "^LISTENER="     "LISTENER=\"`sh_gethostip`\""  false
  sh_sed_file_r_row_include_xxx $dst_file "^JOBS="         "JOBS=\"$def_jobs\"" false
  sudo cp $dst_file $src_file -rf
  ######################################
  #修改STARTDISTCC的值为true。
  #STARTDISTCC="true"
  #在A（server）上，
  #ALLOWEDNETS为连接的客户端范围，按需设置 如:ALLOWEDNETS="192.168.0.0/16"
  #LISTENER为侦听地址，设置为本机ip地址    如: LISTENER="192.168.0.215" （server的ip）
  #JOB为同时可承担的编译任务数目，一般设置为CPU个数+2
  #在B（client）上，不修改以上ALLOWEDNETS和LISTENER的值。
  #其中ALLOWEDNETS采用了CIDR地址规则，在这里，192.168.0.0/16表示只要前16位为192.168的合法IP地址都可以请求编译服务。
  #针对B机器，由于不对外提供编译服务，所以只要将STARTDISTCC设为true即可。
  #######################################
}

function setting_toolchain()
{
  #QCOM8255/gingerbread_house-M7630AABBQMLZA414006/prebuilt/linux-x86/toolchain/arm-eabi-4.4.3/
  #QCOM7225A/trunk/ICS_QRD_R7627USNSKQLYA20452203/prebuilt/linux-x86/toolchain/arm-eabi-4.4.3/
  #MT6575/trunk/ALPS.ICS.MP.V2_W_20120504/prebuilt/linux-x86/toolchain/arm-linux-androideabi-4.4.x
  echoTextBlue "请选择需要设置的工具链 ......"
  result=`sh_menu_select2 "$toolchains_list"`
  toolchain="http://smartphone/repositories/MT6575/trunk/ALPS.ICS.MP.V2_W_20120504/prebuilt/linux-x86/toolchain/$result"
  if test -d $toolchains_dir/$result; then
    echoTextGreen "$toolchains_dir/$result 已经存在!!"
  else
    svn export $toolchain $toolchains_dir/$result
  fi
  #修改/etc/init.d/distcc，将
  #PATH参数加入步骤2的交叉编译工具链编译器位置，以使distcc在接到编译任务时，能找到对应的编译器。
  src_file=/etc/init.d/distcc
  dst_file=/tmp/etc_init.d_distcc
  cp $src_file $dst_file -rf
  sed -i "s#$toolchains_dir/$result/bin:##g" $dst_file
  sed -i "s#PATH=#PATH=$toolchains_dir/$result/bin:#g" $dst_file
  sudo cp $dst_file $src_file -rf
  cat /etc/init.d/distcc |grep PATH
  cat $dst_file |grep PATH
}

function setting_for_server()
{
  #安装必须的软件
  echoTextBlue "Installing $pkgs_list(安装软件) ......"
  sh_dpkg_install "$pkgs_list"
  #设置 /etc/default/distcc
  setting_etc_default_distcc
  #设置工具链
  setting_toolchain
  #重启distcc服务
  sudo service distcc restart
}

function setting_for_clinet()
{
  echoTextBlue "客户端设置......"
  修改android编译脚本，使其支持distcc编译：
  将build/core/combo/TARGET_linux-arm.mk中的TARGET_TOOLS_PREFIX变量改为/usr/lib/distcc/arm-eabi-
  修改build/core/definition.mk, 修改transform-d-to-p为： 
      define transform-d-to-p
      $(hide) if [ -e $(@:%.o=%.d) ];then cp $(@:%.o=%.d) $(@:%.o=%.P); \
      	sed -e 's/#.*//' -e 's/^[^:]*: *//' -e 's/ *\\$$//' \
      		-e '/^$$/ d' -e 's/$$/ :/' < $(@:%.o=%.d) >> $(@:%.o=%.P); \
      	rm -f $(@:%.o=%.d);else cp $(notdir $(@:%.o=%.d)) $(@:%.o=%.P); \
      	sed -e 's/#.*//' -e 's/^[^:]*: *//' -e 's/ *\\$$//' \
      		-e '/^$$/ d' -e 's/$$/ :/' < $(notdir $(@:%.o=%.d)) >> $(@:%.o=%.P); \
      	rm -f $(notdir $(@:%.o=%.d));fi
      endef

  TARGET_TOOLS_PREFIX := prebuilt/$(HOST_PREBUILT_TAG)/toolchain/arm-linux-androideabi-4.4.x/bin/arm-linux-androideabi-
  修改PATH，将distcc编译器路径加入PATH的第一个，并加入交叉编译器路径：
  export PATH=/usr/lib/distcc:<上述第二步交叉编译工具链位置>:$PATH
  此命令可写入profile。
  修改DISTCC_HOSTS，指明支持分布式编译的主机地址：
  export DISTCC_HOSTS=’localhost … … ‘
  make -j8 CC=distcc 根据编译池主机数和本机资源情况调整job数目，以获取最佳性能。
}

function setting_cache()
{
与ccache配合使用
因android官方已经在构建环境中加入了ccache支持，故可以很简单的打开ccache功能以提高编译效率。具体方法为：
$ export USE_CCACHE=1
$ export CCACHE_DIR=/path_of_your_choice/.ccache
$ prebuilt/linux-x86/ccache/ccache -M 20G
其中，20G为推荐值，事实上可以根据编译机器的具体情况进行调整。
在编译期或编译结束后，可以用“ccache -s”命令查看缓存命中情况。
}

function setting_dmucs()
{
  用dmucs实现负载均衡
  选中某台主机作为dmucs服务器。进行配置：
   1. 修改/etc/default/dmucs，启用dmucs：
      将SERVER改为yes
   2. 修改/etc/dmucs.conf 文件，配置编译池：
      根据文件原有说明格式，加入编译池中的主机。
   3. 启动dmucs服务：
      service start dmucs
   4. 在每个编译主机上执行负载发布客户端：
      loadavg -s 主机地址 &
  此时，即可以在发起编译时使用
  make -j8 CC=gethost distcc
  来启用支持负载均衡的分布式编译过程了。
}

#服务器端设置
setting_for_server
#客户端设置
setting_for_clinet
exit

FAQ
1. 执行pump时报python错误这是一个已知的bug，解决方法参见https://bugs.launchpad.net/distcc/+bug/511585
2. 编译时pump报主机不支持cpp
在创建环境变量时需要指明主机支持的编译类型如：
export DISTCC_HOSTS=’localhost compilehost,lzo,cpp’
参考文档:
Using distcc with debian
http://myrddin.org/howto/using-distcc-with-debian/ 
http://xxw8393.blog.163.com/blog/static/37256834201110242241975/
http://blog.csdn.net/rheostat/article/details/7685613
http://my.oschina.net/fanxiao/blog/41645
http://www.biaji.net/wp/biaji/2012/01/android基于distcc的分布式编译及负载均衡的实现/

#通过源代码安装 distcc
function install_distcc_by_source()
{
svn checkout http://distcc.googlecode.com/svn/trunk/ distcc-read-only
sudo apt-get install autogen automake
sudo apt-get install python-dev
cd distcc-read-only
./autogen.sh
CHECKING_DISP python $python_v 
ac_version=`python -c 'import sys; print sys.version[0:5]'`
VERSION_EQUEL python $ac_version $python_v
export PATH=/usr/local/python-2.4.5/bin/:$PATH
./configure --disable-Werror && make && sudo make install
}
ARCH=`arch`
result=`echo $ARCH | grep 64`
if [ "$result" = "" ]; then
    ARCH=i686
    distcc_url=https://www.securehost.com/mirror/debian/pool/main/d/distcc/distcc_3.1-2_i386.deb
else
    ARCH=x86_64
    distcc_url=https://www.securehost.com/mirror/debian/pool/main/d/distcc/distcc_3.1-2_amd64.deb
fi
distcc_file=`basename $distcc_url`

status=`dpkg -s distcc |grep "install ok installed"`
if [ "$status" = "" ]; then
result=`question "是否重新安装?" 1 no`
if [  "$result" = "no" ] ; then
    echoText "安装 distcc " GREEN
    #安装之前必须先清除，不能用 remove ，必须用 purge 否则会出错
    sudo apt-get purge distcc
    if test ! -f $distcc_file ; then
       wget_pkg $distcc_url ./
    fi
    dpkg_install ./$distcc_file
    echoText "安装 distcc 监控程序 distccmon-gnome" GREEN
    sudo apt-get install distccmon-gnome
fi 
fi

#PACKAGE="distcc distcc-pump distccmon-gnome ccache"
#STARTDISTCC="true"               # 自动启动
#ALLOWEDNETS="192.168.39.0/24"    # 允许连接的ip范围
#LISTENER=""                      # 如果要在局域网使用，者必须为空，不然会出现distcc: connection refused
#ZEROCONF="true"                  # 自动查找局域网的distcc服务器，打开就可以不用设置hosts

sudo sed -i "s/STARTDISTCC=\"false\"/STARTDISTCC=\"true\"/g"   /etc/default/distcc
sudo sed -i "s/ALLOWEDNETS=\"127.0.0.1\"/ALLOWEDNETS=\"192.168.1.122 192.168.1.123\"/g"   /etc/default/distcc
sudo sed -i "s/LISTENER=\"127.0.0.1\"/#LISTENER=\"127.0.0.1\"/g"   /etc/default/distcc
sudo /etc/init.d/distcc restart
sudo service avahi-daemon restart  
#sudo /etc/init.d/avahi-daemon restart
echo "查看当前的可用节点"
exit
distcc[29425] (dcc_parse_options) ERROR: unrecognized option in host specification: ,122.168.1.123



distcc是samba开发的分布式编译服务。维护到2.18.3。
现已移到Google Code: http://code.google.com/p/distcc/， 发展到3.1版。
3.x的改进在于支持"pump" 模式，该模式可以将头文件也发送给编译服务器处理。
现有的rpm包分为distcc和distcc-server两部分，不过都是2.18版的。
使用源代码编译也非常快，不费什么时间。
服务端可以使用inetd启动，也可以使用/etc/init.d目录下的脚本启动，推荐使用独立启动，效率更高。
服务器也可手工启动，使用--allow参数指定允许连接的客户端。也可以指定一个网段。
客户端可以使用DIST_HOSTS设置编译服务器，永久使用则使用/etc/下的配置文件。
监视编译过程有图形化的distccmon-gnome,文本的distccmon-text.
distcc支持交叉编译，但交叉编译器的要能在PATH中能找到。
distcc也支持和ccache配合使用。
一切配置好后，make -j N就可以启动编译了。但具体的任务个数好像还是distcc自行决定了，在两台机子的环境下，使用make -j8后，发现配置好机器的上面4个任务，配置差的机器2个任务，并非8个任务。
在设置交叉编译环境变量时还碰到一些问题，似乎distcc没有继承shell的变量。
实际操作中发现编译时间确实大大减小了，非常值得尝试。特别是对于编译动辄数小时的项目。
还有其它一些技术提高编译速度：

There are several tools available separately that enhance or complement distcc:
* ccache caches compiler output to accelerate builds.
* dmucs helps distcc select appropriate servers.
* ccontrol gives centralized control of parallelism, caching and distribution even while the build is running.
* crosstool automates building cross-compilation toolchains.
* distccWebView is a CGI to show which of your servers are up and running.
* tcpbalance is a load-balancing TCP proxy written in Erlang that works well with distcc. 


sudo chmod a+xrw  /etc/distcc/clients.allow
sudo echo '127.0.0.1' > /etc/distcc/clients.allow
echo '192.168.1.120/130' >> /etc/distcc/clients.allow
sudo chmod a-w  /etc/distcc/clients.allow


mkdir 64 -pv
cd 64
ar vx ../distcc_3.1-2_amd64.deb
tar -xvf control.tar.gz
cd -
mkdir 32 -pv
cd 32
ar vx ../distcc_3.1-2_i386.deb
tar -xvf control.tar.gz
cd -
exit


mhf@mhf-desktop:/usr/local/bin$ id distccd
uid=117(distccd) gid=65534(nogroup) 组=65534(nogroup)
distccd:x:117:65534::/:/bin/false


if [ ! -s $DISTCC_LOGFILE ]; then
  touch $DISTCC_LOGFILE
sudo chown distccd:adm /var/log/distccd.log
  chmod 640 $DISTCC_LOGFILE
fi

mkdir 64 -pv
cd 64
ar vx ../distcc_3.1-2_amd64.deb
tar -xvf control.tar.gz
cd -
mkdir 32 -pv
cd 32
ar vx ../distcc_3.1-2_i386.deb
tar -xvf control.tar.gz
cd -

DISTCC_USER=distccd
id $DISTCC_USER > /dev/null 2>&1 || sudo adduser  --system --ingroup nogroup --home / --no-create-home $DISTCC_USER
distccd:x:117:65534::/:/bin/false
注意，根据正则表达式“distcc*”选中了 distcc-pump
注意，根据正则表达式“distcc*”选中了 edos-distcheck
注意，根据正则表达式“distcc*”选中了 distcc-server
注意，根据正则表达式“distcc*”选中了 distccmon-gnome
注意，根据正则表达式“distcc*”选中了 distcc

